﻿

using System;
using System.Runtime.CompilerServices;

namespace NFixedPoint
{
    [Serializable]
    public struct FixedPoint
    {
        public long raw;

        #region 常量

        const int Multiplier = 1 << PRECISION;
        //小数点的位数
        public const int PRECISION = 16;
        //总共位数
        const int TotlaBitCnt = 64;
        //整数位数
        const int IntBitCnt = TotlaBitCnt - PRECISION;

        //小数部分掩码
       public  const long FMask = (long)(ulong.MaxValue >> IntBitCnt);
        //整数部分掩码
        const long IntMask = (-1L & ~FMask);

        //小数部分的取值范围
        const long FRange = FMask + 1;

        public static FixedPoint zero = new FixedPoint(0);
        public static FixedPoint one = new FixedPoint(1);
        public static FixedPoint pi = new FixedPoint(3.1416f);
        public static FixedPoint pi2 = pi * 2;
        public static FixedPoint one_div_pi2 = one / pi2;

        public const long MinVal = long.MinValue >> PRECISION;
        public const long MaxVal = long.MaxValue >> PRECISION;

        #endregion
        #region 构造函数
        /// <summary>
        /// 内部使用
        /// </summary>
        /// <param name="raw"></param>
        private FixedPoint(long raw)
        {
            this.raw = raw;
        }

        public FixedPoint(int v)
        {
            raw = v * Multiplier;
        }
        public FixedPoint(float v)
        {
            raw = (long)Math.Round(v * Multiplier);
        }

        #endregion
        #region 运算符重载
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator +(FixedPoint a, FixedPoint b)
        {
            a.raw += b.raw;
            return a;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator +(FixedPoint a, int b)
        {
            a.raw += (long)b << PRECISION;
            return a;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator +(int a, FixedPoint b)
        {
            b.raw += (long)a << PRECISION;
            return b;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator -(FixedPoint a, FixedPoint b)
        {
            a.raw -= b.raw;
            return a;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator -(FixedPoint a, int b)
        {
            a.raw -= (long)b << PRECISION;
            return a;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator -(int a, FixedPoint b)
        {
            b.raw -= (long)a << PRECISION;
            return b;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator *(FixedPoint a, FixedPoint b)
        {
            //(FRange >> 1)移动小数点会把小数点后面的值抹掉。这里加上一个四舍五入在抹掉。
            return new FixedPoint((a.raw * b.raw + (FRange >> 1)) >> PRECISION);
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator *(FixedPoint a, int b)
        {
            return new FixedPoint((a.raw * new FixedPoint(b).raw + (FRange >> 1)) >> PRECISION);
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator *(FixedPoint a, float b)
        {
            return new FixedPoint((a.raw * new FixedPoint(b).raw + (FRange >> 1)) >> PRECISION);
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator /(FixedPoint a, FixedPoint b)
        {
            return new FixedPoint((a.raw << PRECISION) / b.raw);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator >>(FixedPoint a, int b)
        {
            return new FixedPoint(a.raw >> b);
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator <<(FixedPoint a, int b)
        {
            return new FixedPoint(a.raw << b);
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator -(FixedPoint v)
        {
            return new FixedPoint(-v.raw);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator %(FixedPoint a, FixedPoint b)
        {
            a.raw %= b.raw;
            return a;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator %(FixedPoint a, int b)
        {
            a.raw %= (long)b<<PRECISION;
            return a;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static FixedPoint operator %(int a, FixedPoint b)
        {
            b.raw = ((long)a << PRECISION) % b.raw;
            return b;
        }

        #endregion
        #region 比较运算符重载

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator ==(FixedPoint a, FixedPoint b)
        {
            return a.raw == b.raw;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator !=(FixedPoint a, FixedPoint b)
        {
            return a.raw != b.raw;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator >(FixedPoint a, FixedPoint b)
        {
            return a.raw > b.raw;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator <(FixedPoint a, FixedPoint b)
        {
            return a.raw < b.raw;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator >=(FixedPoint a, FixedPoint b)
        {
            return a.raw >= b.raw;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator <=(FixedPoint a, FixedPoint b)
        {
            return a.raw <= b.raw;
        }

        #endregion
        #region 类型转换
        //显示转换
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static explicit operator FixedPoint(float f)
        {
            return new FixedPoint(f);
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static implicit operator FixedPoint(int f)
        {
            return new FixedPoint(f);
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static explicit operator float(FixedPoint f)
        {
            return (float)f.raw / Multiplier;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static explicit operator int(FixedPoint f)
        {
            return (int)f.raw / Multiplier;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static explicit operator long(FixedPoint f)
        {
            return (long)f.raw;
        }
        public float AsFloat => raw * 1.0f / Multiplier;
        public int AsInt => (int)(raw+(FRange>>1))>>PRECISION;
        public long AsLong => (raw)>>PRECISION;

        #endregion
        #region 其他函数
        public override bool Equals(object obj)
        {
            return raw == ((FixedPoint)obj).raw;
        }
        public override int GetHashCode()
        {
            return raw.GetHashCode();
        }
        public override string ToString()
        {
            return AsFloat.ToString();
        }
        #endregion
    }
}
